#!/usr/bin/env python
#-*- coding:utf-8 -*-

from math import sqrt

class VectorDimensionInconsistent(Exception):
    def __init__(self):
		super(VectorDimensionInconsistent, self).__init__()

class InvalidDimensionNumber(Exception):
    def __init__(self):
		super(InvalidDimensionNumber, self).__init__()

class Similarity(object):
    def __init__(self, item1, item2):
        super(Similarity, self).__init__()
        self._len = len(item1)
        if self._len == 0:
            raise InvalidDimensionNumber()

        if len(item1) != len(item2):
            raise VectorDimensionInconsistent()

        self._item1 = item1
        self._item2 = item2

    def jaccard(self):
        """
        f11 / (f10 + f01 + f11)
        """
        intersect_count = 0
        item1_count = 0
        item2_count = 0
        for i in range(self._len):
            if self._item1[i] != 0 and self._item2[i] != 0: #f11
                intersect_count += 1
            if self._item1[i] != 0 and self._item2[i] == 0: #f10
                item1_count += 1
            if self._item2[i] != 0 and self._item1[i] == 0: #f01
                item2_count += 1
        total_count = item1_count + item2_count + intersect_count
        if total_count == 0:
            return 0
        return intersect_count / float(total_count)

    def eucdistance(self):
        distance = [pow(self._item1[i]-self._item2[i], 2) for i in range(self._len)]
        sum_of_square = sum(distance)
        return 1 / float(1 + sum_of_square)


    def cosine(self):
		#求向量的点积和两个向量的模，然后相除
		xy = sum([self._item1[k] * self._item2[k] for k in range(self._len)])
		mx = sqrt(sum([pow(v, 2) for v in self._item1])) 
		my = sqrt(sum([pow(v, 2) for v in self._item2]))

		return xy / (mx * my)

    def pearson(self):
		#计算均值	
		avg_x = float(sum(self._item1)) / self._len
		avg_y = float(sum(self._item2)) / self._len

		#计算协方差
		co_xy = sum([(self._item1[k] - avg_x) * (self._item2[k] - avg_y) for k in range(self._len)])

		#计算x／y的均方差
		std_x = sum([pow((v - avg_x), 2) for v in self._item1])
		std_y = sum([pow((v - avg_y), 2) for v in self._item2])
		std_xy = sqrt(std_x * std_y)
		if std_xy == 0:
			return 0

		return co_xy / std_xy

    def tanimoto(self):
		xy = sum([self._item1[k] * self._item2[k] for k in range(self._len)])
		mx = sum([pow(v, 2) for v in self._item1]) 
		my = sum([pow(v, 2) for v in self._item2])

		return float(xy) / (mx + my - xy)

if __name__ == "__main__":

    item1 = (24, 4, 12, 14, 0.5)
    item2 = (27, 11, 12, 24, 0.3)
    item3 = (29, 2, 12, 16, 0.5)
    print "item1, item2"
    similar = Similarity(item1, item2)
    print "euc", similar.eucdistance()
    print "cosine", similar.cosine()
    print "pearson", similar.pearson()
    print "tanimoto", similar.tanimoto()

    print "item1, item3"
    similar = Similarity(item1, item3)
    print "euc", similar.eucdistance()
    print "cosine", similar.cosine()
    print "pearson", similar.pearson()
    print "tanimoto", similar.tanimoto()


    v1 = [0, 1, 0, 0, 1, 1, 0, 1]
    v2 = [0, 1, 1, 1, 0, 1, 0, 1]
    v3 = [0, 0, 1, 1, 1, 0, 0, 0]
    s = Similarity(v1, v2)
    print s.cosine()
    print s.jaccard()
    print s.tanimoto()

    s = Similarity(v1, v3)
    print s.cosine()
    print s.jaccard()
    print s.tanimoto()

